import numpy as np

#random seed 
np.random.seed(10)



class UAV:
    def __init__(self, grid_size,id,num_position_action):
        #无人机基础信息
        self.id = id
        self.speed = 1
        
        #无人机能量信息
        self.epsilon = 0.1
        
        #无人机的位置信息
        self.grid_size = grid_size
        self.position = (self.id*2,self.id*3)
        self.num_position_action = num_position_action
        
        # 无人机历史信息
        self.history_position = []
        self.history_length = 5
        self.cnt = 0
        
        # 环绕任务相关属性
        self.target_distance_history = []  # 记录与目标的距离历史
        self.encirclement_contribution = 0  # 合围贡献度
        self.cooperation_score = 0  # 协作得分

    def get_enhanced_state(self, target_position=None, other_uav_positions=None):
        """获取增强的状态表示，包含目标和其他UAV信息"""
        base_state = np.array([self.position[0], self.position[1]])
        
        if target_position is not None:
            # 添加与目标的相对位置和距离
            dx = target_position[0] - self.position[0]
            dy = target_position[1] - self.position[1]
            distance = np.sqrt(dx**2 + dy**2)
            angle = np.arctan2(dy, dx)
            
            target_info = np.array([dx, dy, distance, angle])
            base_state = np.concatenate([base_state, target_info])
        
        if other_uav_positions is not None:
            # 添加与其他UAV的相对信息
            other_info = []
            for other_pos in other_uav_positions:
                if other_pos != self.position:
                    dx = other_pos[0] - self.position[0]
                    dy = other_pos[1] - self.position[1]
                    distance = np.sqrt(dx**2 + dy**2)
                    other_info.extend([dx, dy, distance])
            
            if other_info:
                base_state = np.concatenate([base_state, np.array(other_info)])
        
        return base_state
    
    def update_cooperation_metrics(self, target, all_uav_positions):
        """更新协作相关指标"""
        if target.position:
            distance = np.linalg.norm(np.array(self.position) - np.array(target.position))
            self.target_distance_history.append(distance)
            
            # 保持历史长度
            if len(self.target_distance_history) > 10:
                self.target_distance_history.pop(0)
            
            # 计算合围贡献度
            if self.id in target.surrounding_uavs:
                self.encirclement_contribution += 1
            
            # 计算协作得分（基于与其他UAV的配合程度）
            if len(target.surrounding_uavs) > 1 and self.id in target.surrounding_uavs:
                self.cooperation_score += len(target.surrounding_uavs)
    
    def select_cruise_action(self,action_values):
        # 从有效动作中选择最佳动作
        action = [0,1,2,3]
        self.cnt += 1
        if self.cnt < 200:
            epison = 0.1
        else :
            epison = 0.2
        if np.random.uniform(0, 1) < epison:
            return np.random.choice(action)  # 随机选择一个有效动作
        else:
            # 根据 action_values 选择最佳动作
            best_action = 0
            max_q_value = action_values[best_action]
            for i in action:
                if action_values[i] > max_q_value:
                    best_action = i
                    max_q_value = action_values[i]
        
        return best_action


            
    def execute_cruise_action(self, action):
        """
        根据动作更新位置并消耗对应电量
        假设动作0-3分别表示上下左右移动，动作4表示原地停留
        """
        # 定义每个动作的电量消耗（例如，上下左右移动消耗5单位电量，停留消耗2单位电量）
        
        # 转换为整数列表
        if isinstance(action, list):
            pass
        else:
            action = action.astype(int).flatten().tolist()
        
        # 当前坐标
        x, y = self.position
        distance_per_time = self.speed
        reward1 = 0

        #  # 将张量 action 转换为列表
        # action = [int(i) for i in action.detach().numpy()]

        # 根据动作更新位置
        if action == [1,0,0,0] and y <= self.grid_size - self.speed:  # 向上移动
            y += distance_per_time
        elif action == [0,1,0,0] and y >= self.speed:  # 向下移动
            y -= distance_per_time
        elif action == [0,0,1,0] and x >= self.speed:  # 向左移动
            x -= distance_per_time
        elif action == [0,0,0,1] and x<= self.grid_size -self.speed:  # 向右移动
            x += distance_per_time
        else:
            print(f"无效动作,动作是{action},位置是{x,y}\n")# 停留位置不变
            reward1 -= 10
        
        # # 检查是否超出边界并限制
        # if x < 0:
        #     x = 0  # 如果x小于0，设为最小值0
        #     reward1 -=1000
        #     # print(f"uav:{self.id}hit the wall")
        #     # print(f"uav:{self.id}position:{self.position}")
        # elif x > self.grid_size:
        #     x = self.grid_size - 1  # 如果x超出grid_size，设为最大值grid_size-1
        #     reward1 -=1000
        #     # print(f"uav:{self.id}hit the wall")
        #     # print(f"uav:{self.id}position:{self.position}")
        # if y < 0:
        #     y = 0  # 如果y小于0，设为最小值0
        #     reward1 -= 1000
        #     # print(f"uav:{self.id}hit the wall")
        #     # print(f"uav:{self.id}position:{self.position}")
        # elif y > self.grid_size:
        #     y = self.grid_size - 1  # 如果y超出grid_size，设为最大值grid_size-1
        #     reward1 -= 1000
        #     # print(f"uav:{self.id}hit the wall")
        #     # print(f"uav:{self.id}position:{self.position}")
        
        # 更新位置
        self.position = (x, y)

        if self.position in self.history_position:
            reward1 -= 10
            #print("in the histary")
        
        # 更新历史路径
        self.history_position.append(self.position)
        if len(self.history_position) > self.history_length:
            self.history_position.pop(0)
        
        # 执行电量消耗
        
        return reward1,self.history_position

    def serve_ground_user(self, server1,server2,server3):
        """
        为地面用户提供服务，计算服务的电量消耗和奖励
        """
        if server1 is None: 
            return 1
        elif server2 is None and server1 != self.id:
            return 1
        elif server3 is None and server1 != self.id and server2 != self.id:
            return 1
        else:
            return -1
    def dis_reward(self):
        
        return 0

    
    def find_nearest_user(self, ground_users):
        """
        返回无人机距离未覆盖的所有地面用户中距离最近的距离
        """
        min_distance = float('inf')
        nearest_user = None

        for user in ground_users:
            if not user['covered']:
                distance = np.linalg.norm(np.array(self.position) - np.array(user['position']))
                if distance < min_distance:
                    min_distance = distance
                    nearest_user = user

        return min_distance, nearest_user

    def get_state(self):
        return np.array([self.position[0], self.position[1]])


